fix(head): avoid CSP warnings when disabled#2084
Conversation
🦋 Changeset detectedLatest commit: 28628ee The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
This is the right fix for the right problem. Capturing the CSP-enabled state in the virtual config and keeping Astro.csp behind a lazy getter avoids Astro’s warning on non-CSP sites while preserving JSON-LD script-hash registration for sites that do enable CSP. The change is additive, narrowly scoped, and fits EmDash’s existing virtual-config architecture.
What I checked:
- Diff and full changed files (
EmDashHead.astro,page/metadata.ts,astro/integration/index.ts,virtual-modules.d.ts, tests, changeset). - Virtual-module serialization path (
serializableConfig→generateConfigModule). - All
Astro.csp/insertScriptHash/security.cspusage sites in the repo. - AGENTS.md conventions (changeset, imports, tests).
Headline: implementation is correct, but the new regression test asserts a side-effect order that Promise.all does not guarantee, which is likely to flake. I also noted an optional import-convention alignment.
| expect(getCsp).toHaveBeenCalledOnce(); | ||
| expect(insertScriptHash).toHaveBeenCalledTimes(2); | ||
| expect(insertScriptHash).toHaveBeenNthCalledWith(1, await createSha256CspHash(scripts[0].json)); | ||
| expect(insertScriptHash).toHaveBeenNthCalledWith(2, await createSha256CspHash(scripts[1].json)); |
There was a problem hiding this comment.
[needs fixing] registerJsonLdCspHashes registers hashes with await Promise.all(scripts.map(async …)), so the two async crypto.subtle.digest calls run concurrently. The order in which their insertScriptHash side effects execute is not guaranteed by Promise.all, making the toHaveBeenNthCalledWith(1, …) / toHaveBeenNthCalledWith(2, …) assertions potentially flaky. Since CSP hash order has no functional significance, assert set membership instead of order.
| expect(getCsp).toHaveBeenCalledOnce(); | |
| expect(insertScriptHash).toHaveBeenCalledTimes(2); | |
| expect(insertScriptHash).toHaveBeenNthCalledWith(1, await createSha256CspHash(scripts[0].json)); | |
| expect(insertScriptHash).toHaveBeenNthCalledWith(2, await createSha256CspHash(scripts[1].json)); | |
| const hash0 = await createSha256CspHash(scripts[0].json); | |
| const hash1 = await createSha256CspHash(scripts[1].json); | |
| expect(getCsp).toHaveBeenCalledOnce(); | |
| expect(insertScriptHash).toHaveBeenCalledTimes(2); | |
| expect(insertScriptHash).toHaveBeenCalledWith(hash0); | |
| expect(insertScriptHash).toHaveBeenCalledWith(hash1); |
| * ``` | ||
| */ | ||
| import type { PublicPageContext, PageMetadataContribution } from "../plugins/types.js"; | ||
| import virtualConfig from "virtual:emdash/config"; |
There was a problem hiding this comment.
[suggestion] AGENTS.md’s Imports convention asks for a // @ts-ignore - virtual module comment above imports from virtual:emdash/config. Other files in the repo follow this pattern. Consider adding the comment for consistency, especially since .astro components are excluded from the core tsconfig.json.
| import virtualConfig from "virtual:emdash/config"; | |
| // @ts-ignore - virtual module | |
| import virtualConfig from "virtual:emdash/config"; |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
Re-review of #2084: CSP warning fix
This is the follow-up to the first review of the same PR. My earlier concern was that the new regression test asserted a Promise.all-side-effect order that the runtime does not guarantee, making it likely to flake. That has been addressed.
What I checked
- Diff and full changed files (
EmDashHead.astro,page/metadata.ts,astro/integration/index.ts,virtual-modules.d.ts, the regression tests, and the changeset). - Virtual-module serialization path (
serializableConfig→generateConfigModule). - All
Astro.csp/insertScriptHash/security.cspusage sites in the repo to confirm this is the only affected component. - AGENTS.md conventions: changeset, virtual-module
// @ts-ignore,.jsextensions on internal imports, test coverage, no user-facing admin strings.
Approach
The fix is still the right one for the right problem: capture the CSP-enabled state at build/integration setup time, serialize it through the existing virtual config, and keep Astro.csp access behind a lazy getter so non-CSP sites never trigger Astro's warning. The change is additive, narrowly scoped, and fits EmDash's virtual-config architecture.
Status of prior finding
- Test flakiness resolved. The enabled-path test now independently computes the expected SHA-256 hashes and uses order-insensitive
toHaveBeenCalledWithassertions, so it no longer relies on the insertion order produced byPromise.all. - Import conventions in the changed files align with AGENTS.md (
// @ts-ignore - virtual module,.jsextensions on internal imports, no extension on package imports).
Headline
Implementation is correct, regression coverage is present and now order-safe, and I see no remaining issues. LGTM.
What does this PR do?
Avoids Astro CSP warnings from
EmDashHeadwhen a host project has not enabled Astro's built-in CSP support.This is a follow-up to #1695. The JSON-LD integration currently reads
Astro.cspbefore it knows whether CSP is enabled. Astro 7 warns on every affected production render even when the page does not need CSP handling.The fix:
Astro.csplazy when CSP is disabled;Type of change
Checklist
CONTRIBUTING.mdpnpm --filter emdash typecheckpassespnpm format:checkpassesValidation
pnpm --filter emdash exec vitest run tests/unit/plugins/page-metadata.test.ts- 33 tests passedpnpm --filter emdash typecheckoxlintpnpm format:checkgit diff --checkmain: request returns 200 and logscontext.csp was used ... but CSP was not configured